/**
 * @mxmlc -output=bin/assets/modules/march.swf -external-library-path+=lib/library.swc -debug=false -noplay
 */
package march
{
	import com.greensock.TweenMax;
	import flash.display.Bitmap;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.ui.Keyboard;
	import flash.utils.ByteArray;
	import interfaces.IOperate;
	import march.model.ResultVO;
	import march.model.StepVO;
	import march.view.Army;
	import march.view.Plot;
	import march.view.Result;
	import org.airmvc.View;
	import utils.T;
	import vo.GeneralVO;
	
	/**
	 * ...
	 * @author WLDragon 2014-02-28
	 */
	public class MarchV extends View implements IOperate
	{
		
		public function MarchV()
		{
		}
		
		override public function init():void
		{
			this.scrollRect = new Rectangle(0, 0, 513, 305);
			
			map = new Sprite();
			
			resultPanel = new Result();
			plotPanel = new Plot();
			plotPanel.visible = false;
			addChild(plotPanel);
			
			cursor = new Bitmap(App.asset.getBitmapData("png.strategy.cursor"));
			terrainConfig = T.db.getXml(Cnt.XML_ALGORITHM).terrainStep[0];
			moveTrack = [];
			Lyr.map.addChild(this);
		}
		
		override protected function addListeners():void
		{
			receive(MarchC.INIT_MAP, initMap);
			receive(MarchC.PLACE_DEFENSE, placeDefense);
			receive(MarchC.PLACEEMENT, placement);
			receive(MarchC.INIT_OVER, initOver);
			receive(MarchC.ARMY_MOVE, armyMove);
			receive(MarchC.ARMY_RETREAT, retreat);
			receive(MarchC.ARMY_UPDATE_SOLDIERS,updateArmySoldiers);
			receive(MarchC.TO_SELECT_ARMY, beginToSelectArmy);
			receive(MarchC.UPDATE_RESULT, updateResult);
			receive(MarchC.CHOOSE_RETREAT_GENERALS, chooseGenerals);
			receive(MarchC.EXPEDITION_OVER, expeditionOver);
			receive(MarchC.SHOW_PLOT, showPlot);
			receive(MarchC.SELECT_PLOT_TARGET, selectPlotTarget);
			receive(MarchC.READ_ATTACK, readAttack);
			receive(MarchC.SHOW_MAP,showMap);
		}
		
		private function showMap():void 
		{
			map.visible = true;
			addEventListener(Event.ENTER_FRAME, onFrame);
		}
		
		private function readAttack():void 
		{
			planAct = Cnt.MARCH_ATTACK;
			cursor.visible = true;
			isFollow = false;
			
			Kyb.setOperater(this);
		}
		
		private function updateArmySoldiers():void 
		{
			if(curArmy)
				curArmy.updateSoliders();
			if(targetArmy)
				targetArmy.updateSoliders();
		}
		
		private function selectPlotTarget():void 
		{
			planAct = Cnt.MARCH_PLOT;
			curArmy.unActive();
			map.visible = true;
			plotPanel.visible = false;
			cursor.visible = true;
			isFollow = false;
			
			Kyb.setOperater(this);
		}
		
		private function showPlot(data:Array = null,isClose:Boolean = false,step:int = 0):void 
		{
			if (isClose)
			{
				curArmy.active();
				map.visible = true;
				plotPanel.visible = false;
				cursor.visible = false;
				cursor.x = curArmy.x + 8;
				cursor.y = curArmy.y + 4;
			}
			else
			{
				plotPanel.update(data,step);
				map.visible = false;
				plotPanel.visible = true;
				Msg.instance.show("采用何种计谋?");
			}				
		}
		
		private function expeditionOver():void 
		{
			if(contains(resultPanel))
				removeChild(resultPanel);
				
			while (map.numChildren > 0)
			{
				map.removeChildAt(0);
			}
			if (contains(map))
				removeChild(map);
			
			if(hasEventListener(Event.ENTER_FRAME))
				removeEventListener(Event.ENTER_FRAME, onFrame);
		}
		
		private function chooseGenerals(gs:Array):void 
		{
			resultPanel.chooseGeneral(gs);
		}
		
		private function updateResult(attack:ResultVO,defense:ResultVO):void 
		{
			resultPanel.update(attack, defense);
			if (contains(resultPanel) == false)
				addChild(resultPanel);
				
			if (contains(map))
				removeChild(map);
			
			if(hasEventListener(Event.ENTER_FRAME))
				removeEventListener(Event.ENTER_FRAME, onFrame);
		}
		
		private function retreat(isDefense:Boolean = false):void 
		{
			if (isDefense)
			{
				map.removeChild(targetArmy);
				defenseLength--;
			}
			else
			{
				map.removeChild(curArmy);
				beginToSelectArmy();
			}
		}
		
		private function armyMove(step:int):void 
		{
			this.moveSteps = step;
			moveTrack.length = 0;
			isFollow = true;
			cursor.visible = false;
			planAct = Cnt.MARCH_MOVE
			Kyb.setOperater(this);
			Msg.instance.show("移动至何处?\n请策马",130,350);
		}
		
		private function initOver():void 
		{
			limitRect = null;
			map.addChild(cursor);
			addEventListener(Event.ENTER_FRAME, onFrame);
			beginToSelectArmy();
		}
		
		private function beginToSelectArmy():void 
		{
			isFollow = false;
			cursor.visible = true;
			if(curArmy)
			{
				curArmy.unActive();
				curArmy = null;
			}
			
			Msg.instance.show("向哪位武将下达命令？", 140, 340);
			
			planAct = Cnt.MARCH_SELECT;
			
			Kyb.setOperater(this);
		}
		
		public function execute(keyCode:int):void
		{
			switch (keyCode)
			{
				case Keyboard.A: 
					if (cursor.x > 8)
						nextStep("x", -clipWidth);
					break;
				case Keyboard.D: 
					if (cursor.x < 1000)
						nextStep("x", clipWidth);
					break;
				case Keyboard.W: 
					if (cursor.y > 8)
						nextStep("y", -clipWidth);
					break;
				case Keyboard.S: 
					if (cursor.y < 584)
						nextStep("y", clipWidth);
					break;
				case Keyboard.SPACE:
					if (limitRect != null)
						send(MarchC.PLACEEMENT_NEXT);
					else
						judgeAct();
					break;
				case Keyboard.R:
					handleRKey();
					break;
			}
		}
		
		private function handleRKey():void
		{
			if (planAct == Cnt.MARCH_MOVE)
			{
				if (moveTrack.length > 0)
				{
					var stepVO:StepVO = moveTrack.pop();
					moveSteps += stepVO.cost;
					curArmy.x = stepVO.x;
					curArmy.y = stepVO.y;
					cursor.x = curArmy.x + 8;
					cursor.y = curArmy.y +4;
					send(MarchC.UPDATE_STEP, moveSteps);
				}
			}
			else if (planAct == Cnt.MARCH_SELECT || planAct == Cnt.MARCH_CHECK)
			{
				var a:Army = testArmy(cursor.x - 8, cursor.y - 4, 0, map.numChildren - 1);
				if (a != null)
				{
					planAct = Cnt.MARCH_CHECK;
					send(MarchC.CHECK_ARMY,a.general);
				}
			}
			else if (planAct == Cnt.MARCH_PLOT)
			{
				showPlot();
			}
			else if (planAct == Cnt.MARCH_ATTACK)
			{
				send(MarchC.REQUEST_TO_SELECT_ARMY);
			}
		}
		
		private function judgeAct():void 
		{
			var army:Army;
			if (planAct == Cnt.MARCH_SELECT)
			{
				army = testArmy(cursor.x - 8,cursor.y - 4,defenseLength,map.numChildren - 1);
				if (army)
				{
					curArmy = army;
					curArmy.active();
					cursor.visible = false;
					isFollow = true;
					Msg.instance.show("");
					send(MarchC.SELECT_ARMY, curArmy.general);
				}
			}
			else if (planAct == Cnt.MARCH_MOVE)
			{
				send(MarchC.REQUEST_TO_SELECT_ARMY);
			}
			else if (planAct == Cnt.MARCH_ATTACK)
			{
				army = testArmy(cursor.x - 8, cursor.y - 4, 0, defenseLength);
				if (army)
				{
					var dx:int = Math.abs(curArmy.x - army.x);
					var dy:int = Math.abs(curArmy.y - army.y);
					//var i:int = (army.y / 32) * col + army.x / 32;//获取地形用
					if ((dx == 32 && dy == 0) || (dx == 0 && dy == 32))
					{
						if(hasEventListener(Event.ENTER_FRAME))
							removeEventListener(Event.ENTER_FRAME, onFrame);
							
						curArmy.unActive();
						send(MarchC.START_ATTACK,army.general);
						map.visible = false;
						targetArmy = army;
					}
					else
					{
						Msg.instance.show("敌方部队太远，无法攻击",125,340);
					}
				}
			}
			else if (planAct == Cnt.MARCH_PLOT)
			{
				army = testArmy(cursor.x - 8, cursor.y - 4, 0, defenseLength);
				if (army)
				{
					targetArmy = army;
					
					var dx2:int = Math.abs(curArmy.x - army.x) / 32;
					var dy2:int = Math.abs(curArmy.y - army.y) / 32;
					var i:int = (army.y / 32) * col + army.x / 32;
					send(MarchC.RELEASE_PLOT, army.general, dx2, dy2, mapData[i]);
				}
			}
			else if (planAct == Cnt.MARCH_CHECK)
			{
				send(MarchC.REQUEST_TO_SELECT_ARMY);
			}
			
		}
		
		private function nextStep(prop:String, stepLength:int):void
		{
			if (isFollow)
			{
				if (canNextStep(prop, stepLength))
				{
					cursor[prop] += stepLength;
					curArmy[prop] += stepLength;
				}
			}
			else
			{
				cursor[prop] += stepLength;
			}
		}
		
		private function canNextStep(prop:String, stepLength:int):Boolean
		{
			var nx:int = prop == "x" ? curArmy.x + stepLength : curArmy.x;
			var ny:int = prop == "y" ? curArmy.y + stepLength : curArmy.y;
			var a:Army = testArmy(nx, ny, 0, map.numChildren - 1);
			if (a != null)
				return false;
				
			if (limitRect != null)
			{
				if (nx < limitRect.x || nx > limitRect.x + limitRect.width || ny < limitRect.y || ny > limitRect.y + limitRect.height)
					return false;
			}
			else
			{
				var i:int = (ny / 32) * col + nx / 32;
				var type:int = mapData[i];
				var x:XML = terrainConfig.terrain.(@type == type).soldiers.(@min <= curArmy.general.soliders && curArmy.general.soliders <= @max)[0];
				var cost:int = int(x.item.(@type == curArmy.general.armyType)[0]);
				if (moveSteps >= cost)
				{
					moveSteps -= cost;
					send(MarchC.UPDATE_STEP, moveSteps);
					//添加到队列以便恢复
					moveTrack.push(new StepVO(curArmy.x,curArmy.y,cost));
					return true;
				}
				else
				{
					return false;
				}
			}
			
			return true;
		}
		
		private function initMap(mapId:int, callback:Function):void
		{
			castleId = mapId;
			var b:ByteArray = new ByteArray();
			b.writeBytes(T.db.getMapData_B(mapId));
			b.position = 0;
			b.readInt(); //移除编辑器用的数据
			b.readInt();
			row = b.readByte(); //行
			col = b.readByte(); //列
			clipWidth = b.readByte(); //纹理块的宽
			clipHeight = b.readByte(); //纹理块的高
			
			var tx:int;
			var ty:int;
			for (var i:int = 0; i < row; i++)
			{
				ty = clipHeight * i;
				for (var j:int = 0; j < col; j++)
				{
					tx = clipWidth * j;
					map.graphics.beginBitmapFill(T.texture.getData(b.readByte()));
					map.graphics.drawRect(tx, ty, clipWidth, clipHeight);
				}
			}
			map.graphics.endFill();
			b = null;
			
			var d:ByteArray = new ByteArray();
			d.writeBytes(T.db.getMapData_D(mapId));
			d.position = 0;
			mapData = new Vector.<int>();
			while (d.bytesAvailable > 0)
			{
				mapData.push(d.readByte());
			}
			d = null;
			
			callback.call();
			map.visible = true;
			addChild(map);
		}
		
		private function placeDefense(defense:Array):void
		{
			//找出守方主城位置，布置军队
			var i:int = mapData.indexOf(6);
			var p:Point = new Point(i % col * 32, (i / col >> 0) * 32);
			var def:Army = new Army(); //主将
			def.x = p.x;
			def.y = p.y;
			def.update(defense[0], false, true);
			map.addChild(def);
			for (var j:int = 0, len:int = defense.length - 1; j < len; j++)
			{
				def = new Army(); //其他武将
				def.x = p.x + DEFENSE_POINTS[j].x;
				def.y = p.y + DEFENSE_POINTS[j].y;
				def.update(defense[j + 1], false);
				map.addChild(def);
			}
			
			//屏幕对准防守方
			map.x = 240 - p.x;
			map.y = 136 - p.y;
			
			Msg.instance.show("安置武将于何处？\n请请指定地点", 140, 340, 12, moveToAttackSite);
		
		}
		
		private function moveToAttackSite():void
		{
			//计算攻方出现的位置，手动布置军队
			var xAttack:XML = T.db.getXml(Cnt.XML_CASTLE).castle.(@id == Gbl.activeCastle.id)[0];
			var xDefense:XML = T.db.getXml(Cnt.XML_CASTLE).castle.(@id == castleId)[0];
			var p1:Point = new Point(xAttack.@x, xAttack.@y);
			var p2:Point = new Point(xDefense.@x, xDefense.@y);
			var mp:Point;
			if (p1.x <= p2.x && p1.y <= p2.y)
			{
				mp = new Point(0, 0); //左上
				limitRect = new Rectangle(0, 0, 224, 128);
			}
			else if (p1.x >= p2.x && p1.y <= p2.y)
			{
				mp = new Point(-509, 0); //右上
				limitRect = new Rectangle(768, 0, 224, 128);
			}
			else if (p1.x >= p2.x && p1.y >= p2.y)
			{
				mp = new Point(-509, -335); //右下
				limitRect = new Rectangle(768, 480, 224, 128);
			}
			else
			{
				mp = new Point(0, -335); //左下
				limitRect = new Rectangle(0, 480, 224, 128);
			}
			
			var time:Number = Math.sqrt(Math.pow(map.x - mp.x, 2) + Math.pow(map.y - mp.y, 2)) / 470;
			TweenMax.to(map, time, {x: mp.x, y: mp.y, onComplete: tweenComplete});
		}
		
		private function tweenComplete():void
		{
			Msg.instance.show("");
			send(MarchC.PLACEEMENT_NEXT);
			Kyb.setOperater(this);
		}
		
		private function placement(g:GeneralVO,defenseLength:int,isCaptain:Boolean = false):void
		{
			this.defenseLength = defenseLength;
			var army:Army = new Army();
			army.update(g, true, isCaptain);
			var px:int = limitRect.x + 128;
			var py:int = limitRect.y + 32;
			
			var i:int;
			while (testArmy(px, py, defenseLength, map.numChildren) != null)
			{
				px = limitRect.x + i % 8 * 32;
				py = limitRect.y + (i / 8 >> 0) * 32;
				i++;
			}
			
			army.x = px;
			army.y = py;
			map.addChild(army);
			
			isFollow = true;
			
			cursor.x = army.x + 8;
			cursor.y = army.y + 4;
			
			if (curArmy != null)
				curArmy.unActive();
			
			curArmy = army;
			curArmy.active();
		}
		
		/**
		 * 检查在指定坐标上是否有军队
		 * @param	tx    x坐标
		 * @param	ty    y坐标
		 * @param	start map子显示列表的索引开始位置
		 * @param	end   map子显示列表的索引结束位置
		 * @return
		 */
		private function testArmy(tx:int,ty:int,start:int,end:int):Army
		{
			for (var i:int = start; i < end; i++) 
			{
				var a:Army = map.getChildAt(i) as Army;
				if (a.x == tx && a.y == ty)
					return a;
			}
			
			return null;
		}
		
		private function onFrame(e:Event):void
		{
			var p:Point = map.localToGlobal(new Point(cursor.x, cursor.y));
			if (p.x < 180 && map.x < 0)
				map.x += 8;
			
			if (p.x > 351 && map.x > -509)
				map.x -= 8;
			
			if (p.y < 100 && map.y < 0)
				map.y += 8;
			
			if (p.y > 205 && map.y > -335)
				map.y -= 8;
		}
		
		private var castleId:int;
		private var map:Sprite;
		private var mapData:Vector.<int>;
		private var row:int;
		private var col:int;
		private var clipWidth:int;
		private var clipHeight:int;
		/**机动总数，与移动相关*/
		private var moveSteps:int;
		/**每步移动的记录队列*/
		private var moveTrack:Array;
		/**敌方军队的数量*/
		private var defenseLength:int;
		/**布置武将时限制活动范围的矩形*/
		private var limitRect:Rectangle;
		/**下一步准备的行动Cnt.MARCH_*/
		private var planAct:int;
		private var terrainConfig:XML;
		/**战斗结果*/
		private var resultPanel:Result;
		/**计谋显示面板*/
		private var plotPanel:Plot;
		
		private var cursor:Bitmap;
		private var curArmy:Army;
		private var targetArmy:Army;
		/**军队是否跟着光标移动,此时光标隐藏*/
		private var isFollow:Boolean;
		/**守方的初始化阵型,从第二个武将到第十个武将*/
		private const DEFENSE_POINTS:Array = [{x: -32, y: 0}, {x: 0, y: -32}, {x: 32, y: 0}, {x: 0, y: 32}, {x: -32, y: -32}, {x: 32, y: -32}, {x: 32, y: 32}, {x: -32, y: 32}, {x: 64, y: 64}];
	}

}